/*
 * Copyright (C) 2007,2008  Jonathan Hendler
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 * 
 * The authors can be contacted at: 
 * @author Jonathan Hendler [jonathan DOT hendler AT google DOT com]
 * 
 * @license GPLv2
 */
/**
 * in NYMRL, sqlite is mostly in a read only setting.
 * Also, each user get's their own DB, so concucrrency issues are also low for them.
 * 
 * As for speed, sqlite seems to perform very well for all the features provided
 * http://www.sqlite.org/cvstrac/wiki?p=SpeedComparison
 * http://sqlite.phxsoftware.com/forums/p/174/622.aspx
 * 
 * */

#ifndef SQLITE_HELPER_SET_
#define SQLITE_HELPER_SET_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "nymrl_log.h"
#include "sqlite3.h"


#ifndef TRUE
#define TRUE		1==1
#endif /* !defined TRUE */

#ifndef FALSE
#define FALSE		0==2
#endif /* !defined FALSE */

#define NYMRL_SQLITE_CACHE_SIZE 23000

/**
 * (c) 2007 Jonathan Hendler
 * 
 * 
 * //http://www.sqlite.org/datatype3.html
 * @todo check autocommit
 * 
 * */
//DEFINES
//Can swap for UTF-16 sqlite3_open16
#define NYMRL_SQLITE_OPEN sqlite3_open
#define NYMRL_SQLITE_CLOSE sqlite3_close
#define NYMRL_SQLITE_RESULT_CLEANUP if (result) { sqlite3_free_table(result);} if (sql) { sqlite3_free(sql);}
//macro for getting array length
#define NYMRL_COUNT(x) (sizeof (x) / sizeof *(x))

#define NYMRL_SQLITE_GET_RESULTS \
	char ** result;\
	char * err;\
	int rc, nrows,ncols;\
	rc = sqlite3_get_table(db,sql,&result,&nrows,&ncols,&err);\
	if (rc != SQLITE_OK){\
		if(err != NULL){\
			printf("nymrl_sqlite_get_results() err %i: %s\n%s\n",rc,err,sql);\
			sqlite3_free(err);\
			sqlite3_free(sql);\
			 }	result = NULL; }


////int nrows = NYMRL_COUNT(result);
#define NYMRL_RESULT_ITERATOR(result,ncols,nrows,i,j) \
	int i,j;\
	for(i=0;i< nrows ;i++){\
		for (j=0;j<ncols;j++){
	
#define NYMRL_SQLITE_GET_AND_ITERATE(result,ncols,nrows,i,j)  NYMRL_SQLITE_GET_RESULTS; NYMRL_RESULT_ITERATOR(result,ncols,nrows,i,j)

#define NYMRL_SQLITE_STEP_INIT \
	char * column_value = "";\
	const char *tail;\
	int rc,j,ncols;\
	char * err = NULL;\
	sqlite3_stmt *stmt;\
	int changes = 0,iter=0;\


#define NYMRL_SQLITE_STEP_STEPPER(column_value,db,sql,j)  \
	rc = sqlite3_prepare(db, sql, (int)strlen(sql), &stmt, &tail);\
	if(rc != SQLITE_OK) {\
		err = malloc(256);\
		sprintf(err, "%s",sqlite3_errmsg(db));\
		sqlite3_free(sql);\
	}\
	if(!err){\
		rc = sqlite3_step(stmt);\
		ncols = sqlite3_column_count(stmt);\
		while(rc == SQLITE_ROW) {\
	        for(j=0; j < ncols; j++) {\
	        	
#define NYMRL_SQLITE_STEP_ITERATE(column_value,db,sql,j) \
	NYMRL_SQLITE_STEP_INIT;\
	NYMRL_SQLITE_STEP_STEPPER(column_value,db,sql,j)
	        	
	        	
//column_value = sqlite3_column_text(stmt, j);


#define NYMRL_SQLITE_STEP_ITERATE_CLOSE \
			}\
			iter;\
			rc = sqlite3_step(stmt);\
		}\
	}\
	
#define NYMRL_SQLITE_STEP_ITERATE_CLEANUP \
	sqlite3_finalize(stmt);\
	sqlite3_free(sql);\




//#define NYMRL_PRINT_ERROR(a,...) fprintf(stdout,a,...)

int nymrl_sqlite_close(sqlite3 * db);
char * nymrl_sqlite_create_sql(const char * sql,...);
void nymrl_sqlite_open(const char * dbname, sqlite3 ** new_db_);
void nymrl_sqlite_print_debug_info(sqlite3 *db,const char * sql);
inline void _nymrl_sqlite_print_debug_info(sqlite3 *db, const char * sql);

//open transaction
//close transaction

//transactional insert/update/delete
/*
 * non transactional insert/update/delete
 * usage: 
 * 	int cid 1
 *  char * sql = "insert %i,'%q'"
 *  nymrl_sqlite_exec(db,sql, cid,"value"
 */
inline int nymrl_sqlite_exec(sqlite3 *db, char * sql);
inline int nymrl_sqlite_exec_changes(sqlite3 *db,char * sql,char ** err);

sqlite_int64 nymrl_sqlite_insert_and_get_id(sqlite3 *db, char * sql);

void nymrl_print_result(char ** result,int nrows,int ncols);
inline char ** nymrl_sqlite_get_results(int print ,sqlite3 *db, char * sql );
char * nymrl_sqlite_copy_single_value( void * item,int count, int unit_size);
int nymrl_sqlite_drop_table(sqlite3 *db,   char * table_name);
char * nymrl_sqlite_get_single_value(sqlite3 *db,char * sql );
 

#endif

/**
 * http://www.sqlite.org/lockingv3.html
 * 
http://www.sqlite.org/c3ref/mprintf.html
This second example is an SQL syntax error. As a general rule you should always use %q instead of %s when inserting text into a string literal.

The %Q option works like %q except it also adds single quotes around the outside of the total string. Or if the parameter in the argument list is a NULL pointer, %Q substitutes the text "NULL" (without single quotes) in place of the %Q option. So, for example, one could say:

    char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
    sqlite3_exec(db, zSQL, 0, 0, 0);
    sqlite3_free(zSQL);

The code above will render a correct SQL statement in the zSQL variable even if the zText variable is a NULL pointer.

The "%z" formatting option works exactly like "%s" with the addition that after the string has been read and copied into the result, sqlite3_free() is called on the input string.

See also lists of Objects, 

 * 
 * */
